package net.crazyadam.activity;

import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.TextView;
import net.crazyadam.R;
import net.crazyadam.audio.Constant;

/**
 * Copyright by <a href="http://crazyadam.net"><em><i>Joseph J.C. Tang</i></em></a> <br/>
 * Email: <a href="mailto:jinntrance@gmail.com">jinntrance@gmail.com</a>
 *
 * @author joseph
 * @version 1.0
 * @since 10/17/12 10:50 AM
 */
public class PlaySound extends Activity {
    // originally from http://marblemice.blogspot.com/2010/04/generate-and-play-tone-in-android.html
    // and modified by Steve Pomeroy <steve@staticfree.info>
    public static int length=1;
    public final static double freqSync = 19500; // hz
    public final static double freqStart = 21000; // hz
    public final static double freqStep = 200; // hz
    public static final int sampleRate = Constant.SAMPLE_RATE;
    private final double duration =1; // seconds
    public static final double codedDuration = 0.04;// seconds
    private int id;

    private static int sampleLength=(int) ((length+1)*codedDuration*sampleRate);
    private final int numSamples = ((int) (duration*sampleRate))/10*10 ;//10ms,必須爲10的倍數



    private  short generatedSnd[] =new short[sampleLength];

    private Handler handler = new Handler();
    private boolean playable = true;
    private AudioTrack audioTrack;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.audio);
        TextView text = (TextView) findViewById(R.id.text);
        text.setText("generating audio");
    }


    public void start(View view) {

        // Use a new tread as this can take a while
        TextView v = (TextView) findViewById(R.id.userId);
        id =Integer.parseInt(String.valueOf(v.getText()));
        final Thread thread = new Thread() {
            public void run() {
                genSound();
                playSound();
/*                while (playable) {
                    handler.post(new Runnable() {
                        public void run() {
                            playSound();
                        }
                    });
                    try {
                        Thread.sleep(40l);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }*/
            }
        };
        thread.start();

    }
    public void stop(View view) {
        playable = false;
        audioTrack.release();
    }

    public static short[] genSound(int id, int numSamples, double freqOfTone, int sampleRate) {
        double sample[];

        //length=count(id); //
        // fill out the array
//        for (int i = 0; i < numSamples; i ++) {
//                double data = genWave(freqOfTone, sampleRate, i, id);
//                    sample[i] = data;
//        }

        sample=genWave(freqStart,freqStart+freqStep,id) ;
        short[] generatedSnd = new short[sample.length];
        // convert to 16 bit pcm sound array
        int idx = 0;
        for (double dVal : sample) {
            // scale to maximum amplitude
            final short val = (short) ((dVal * Short.MAX_VALUE));
            generatedSnd[idx++] = val;
            // in 16 bit wav PCM, first byte is the low order byte
//            generatedSnd[idx++] = (byte) (val & 0x00ff);
//            generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);

        }
        return generatedSnd;
    }

    /**
     * @see AudioRecorder#decode(float[])
     * @param freqOfTone 开始频率作为标识频率，每200Hz编码一位
     * @param sampleRate 采样率
     * @param index  第多少個樣本
     * @param code 编码id，最大 2<sup>8</sup>
     * @return  瞬时强度
     */
    private static double genWave(double freqOfTone, int sampleRate, int index,int code) {
        double a=Math.sin(2 * Math.PI * freqOfTone * index / sampleRate)/(length+1);
        for(int i=length;i>0;i--,code>>=1)
           if(1==(code&1))
               a+=genWave(freqOfTone+i*freqStep,1.0*index / sampleRate)/(length+1);
//        return index<40?a*index/40:a*0.9999;
        return a*0.9999;//TODO
    }

    /**
     * 编码
     * @param freqOne 传输值为1的编码
     * @param freqZero 传输值为0的编码
     * @param code 要传的数据
     * @return  调制后的数据
     */
    private  static double[]  genWave(double freqOne,double freqZero,int code){
        double  [] samples=new double[sampleLength];
        for(int j=0;j<codedDuration*sampleRate;j++){
            samples[j]= genWave(freqSync, j * 1.0 / sampleRate);    //同步时所需额外调制声音
        }
        for(int i=length;i>0;i--,code>>=1){
                for(int j=0;j<codedDuration*sampleRate;j++){
                    double index=(length-i+1)*codedDuration*sampleRate+j;
                    if(1==(code&1))
                        samples[(int) index]= genWave(freqOne+(length-i)*freqStep, index / sampleRate);
                    else
                        samples[(int) index]= genWave(freqZero+(length-i)*freqStep, index / sampleRate);
                }
        }
/*        for(int j= (int) ((length+1)*codedDuration*sampleRate);j<codedDuration*sampleRate;j++){
            samples[j]= genWave(freqSync, j*1.0 /sampleRate);    //同步时所需额外调制声音
        }*/
       return  samples;
    }

    /**
     * 三角函数编码
     * @param frequency 要调制的频率
     * @param time 要调制的时刻
     * @return 调制结果
     */
    private  static double genWave(double frequency,double time){
        return Math.cos(2 * Math.PI * frequency * time);
    }
    private  static double genWaveWithSync(double frequency,double time){
        return Math.cos(2 * Math.PI * frequency * time)+Math.sin(2 * Math.PI * freqSync * time);
    }
    private static int count(int code){
        int count=0;
        do{
            if(1==(code%2)) count++;
        }while(0!=(code>>=1));
        return count;
    }

    private short[] genSound() {
        int min=AudioTrack.getMinBufferSize(sampleRate,AudioFormat.CHANNEL_OUT_MONO,AudioFormat.ENCODING_PCM_16BIT);
        short [] samples=genSound(this.id, numSamples, freqStart, sampleRate);
        //播放数据buffer不能小于 getMinBufferSize
        if(samples.length>=min)
            this.generatedSnd=samples;
        else {
            this.generatedSnd=new short[min];

            System.arraycopy(samples,0,this.generatedSnd,min-samples.length-1,samples.length);
        }
        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                sampleRate, AudioFormat.CHANNEL_OUT_MONO,
                AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length,
                AudioTrack.MODE_STREAM);
        audioTrack.write(generatedSnd, 0, generatedSnd.length);
        return this.generatedSnd;
    }


    void playSound()  {
         if(null!=audioTrack)
             audioTrack.release();
        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                sampleRate, AudioFormat.CHANNEL_OUT_MONO,
                AudioFormat.ENCODING_PCM_16BIT, generatedSnd.length,
                AudioTrack.MODE_STATIC);
        audioTrack.write(generatedSnd,0,generatedSnd.length);
        audioTrack.setLoopPoints(0,generatedSnd.length/2,-1);
        audioTrack.play();

    }
}
